package com.stone.design.mode.state.spring;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.statemachine.StateMachine;
import org.springframework.statemachine.persist.StateMachinePersister;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 订单服务实现
 * 订单业务类，结合状态机来完成订单业务
 *
 * @author wenpan 2022/06/18 17:28
 */
@Slf4j
@Service("orderService")
public class OrderServiceImpl implements OrderService {

    /**
     * 订单状态机
     */
    @Autowired
    private StateMachine orderStateMachine;

    /**
     * 状态持久化器
     */
    @Autowired
    private StateMachinePersister persister;

    private final AtomicInteger id = new AtomicInteger(0);

    /**
     * 实际使用时这里是Redis或数据库
     */
    private final Map<Integer, Order> orders = new HashMap<>();

    /**
     * 创建订单
     *
     * @return com.stone.design.mode.state.spring.Order
     */
    @Override
    public Order create() {
        Order order = new Order();
        order.setId(id.incrementAndGet());
        order.setStatus(OrderStatus.WAITE_PAYMENT);
        orders.put(order.getId(), order);
        return order;
    }

    /**
     * 支付订单
     *
     * @param id 订单ID
     * @return com.stone.design.mode.state.spring.Order
     */
    @Override
    public Order pay(int id) {
        // 查到待支付的临时订单
        Order order = orders.get(id);
        log.info("线程名称：[{}], 尝试支付，订单号：[{}]", Thread.currentThread().getName(), id);
        Message<OrderStateChangeEvent> message = MessageBuilder
                .withPayload(OrderStateChangeEvent.PAYED)
                .setHeader("order", order).build();
        if (!sendEvent(message, order)) {
            log.error("=============>>>>>>>>>>>>线程名称：[{}], 支付失败，状态异常，订单号：[{}]", Thread.currentThread().getName(), id);
        }

        return orders.get(id);
    }

    /**
     * 订单发货
     *
     * @param id 订单ID
     * @return com.stone.design.mode.state.spring.Order
     */
    @Override
    public Order deliver(int id) {
        Order order = orders.get(id);
        log.info("线程名称：[{}], 尝试发货，订单号：[{}]", Thread.currentThread().getName(), id);
        Message<OrderStateChangeEvent> message = MessageBuilder
                .withPayload(OrderStateChangeEvent.DELIVERY)
                .setHeader("order", order).build();
        if (!sendEvent(message, order)) {
            log.error("=============>>>>>>>>>>>>线程名称：[{}], 发货失败，状态异常，订单号：[{}]", Thread.currentThread().getName(), id);
        }

        return orders.get(id);
    }

    /**
     * 订单收货
     *
     * @param id 订单ID
     * @return com.stone.design.mode.state.spring.Order
     */
    @Override
    public Order receive(int id) {
        Order order = orders.get(id);
        log.info("线程名称：[{}], 尝试收货，订单号：[{}]", Thread.currentThread().getName(), id);
        Message<OrderStateChangeEvent> message = MessageBuilder
                .withPayload(OrderStateChangeEvent.DELIVERY)
                .setHeader("order", order).build();
        if (!sendEvent(message, order)) {
            log.error("=============>>>>>>>>>>>>线程名称：[{}], 收货失败，状态异常，订单号：[{}]", Thread.currentThread().getName(), id);
        }

        return orders.get(id);
    }

    /**
     * 发送事件
     *
     * @param message 消息
     * @param order   订单
     * @return boolean true / false
     */
    private boolean sendEvent(Message<OrderStateChangeEvent> message, Order order) {
        boolean result = false;
        try {
            // 启动状态机
            orderStateMachine.start();
            // 尝试恢复状态机状态
            persister.restore(orderStateMachine, order);
            // 添加延迟用于线程安全测试
            Thread.sleep(1000);
            // 使用状态机发送事件
            result = orderStateMachine.sendEvent(message);
            // 持久化状态机状态
            persister.persist(orderStateMachine, order);
        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            // 停止状态机
            orderStateMachine.stop();
        }

        return result;
    }

    /**
     * 获取订单
     *
     * @return java.util.Map
     */
    @Override
    public Map<Integer, Order> getOrders() {
        return orders;
    }
}
